# Copyright (c) 2018 Presto Labs Pte. Ltd.
# Author: xguo

import time

try:
  import bitmex
except ImportError as e:
  pass

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin.exchange.util.rate_limit import RateLimiter
from coin.exchange.base.kr_rest.rest_client_base import RestUpdate


class BitmexNativePrivateClient(object):
  def __init__(self, key_file, timeout=5, test=False):
    key = AuthKey.from_file(key_file=key_file)
    self._client = bitmex.bitmex(api_key=key.access_key, api_secret=key.secret_key, test=test)
    self.timeout = timeout
    self.rate_limit = RateLimiter(300, 5 * 60)

  def _query_nocheck(self, endpoint, method, params):
    if params:
      params = {key: value for key, value in params.items() if value is not None}
    req_timestamp = time.time()
    fut = getattr(getattr(self._client, endpoint), method)(**params)
    json_msg, response = fut.result(timeout=self.timeout)
    if response.status_code == 200:
      res_timestamp = time.time()
      return RestUpdate(req_timestamp, res_timestamp, json_msg, status=200)
    else:
      res_timestamp = time.time()
      return RestUpdate(req_timestamp, res_timestamp, None, status=response.status_code)

  def _query(self, endpoint, method, params=None, disable_rate_limit=False):
    if not disable_rate_limit:
      while not self.rate_limit.check():
        time.sleep(0.1)
    else:
      self.rate_limit.check()
    params = params or {}
    return self._query_nocheck(endpoint, method, params=params)

  def query_user_wallet(self):
    endpoint = 'User'
    method = 'User_getWallet'
    return self._query(endpoint, method)

  def query_user_margin(self):
    endpoint = 'User'
    method = 'User_getMargin'
    return self._query(endpoint, method)

  def query_orders(self, symbol, status=None):
    assert status in ['Open', 'Fill', 'New', None]
    endpoint = 'Order'
    method = 'Order_getOrders'
    if status:
      msg_filter = '{"ordStatus": "%s"}' % status
    else:
      msg_filter = None
    params = {'symbol': symbol, 'filter': msg_filter, 'reverse': True}
    return self._query(endpoint, method, params)

  def query_position(self):
    endpoint = 'Position'
    method = 'Position_get'
    return self._query(endpoint, method)

  # Add some risk control mechanism
  def query_order_new(self, symbol, side, price, order_qty, client_order_id=None):
    endpoint = 'Order'
    method = 'Order_new'
    assert side in ['Buy', 'Sell']
    assert order_qty > 0
    assert price > 0
    params = {
        'symbol': symbol,
        'side': side,
        'orderQty': order_qty,
        'price': price,
        'clOrdID': client_order_id,
    }
    return self._query(endpoint, method, params)

  def query_order_cancel(self, order_id):
    endpoint = 'Order'
    method = 'Order_cancel'
    params = {
        'orderID': order_id,
    }
    return self._query(endpoint, method, params)

  def query_order_cancel_all(self, symbol=None):
    endpoint = 'Order'
    method = 'Order_cancelAll'
    if symbol:
      params = {
          'symbol': symbol,
      }
    else:
      params = None
    return self._query(endpoint, method, params)
